#include "echo.pb.h"

#include <stdio.h>
#include <functional>
#include <memory>

#include <base/logger.h>
#include <net/tcp_client.hpp>
#include <net/tcp_connection.hpp>
#include <protorpc/rpc_channel.hpp>

static const int kRequests = 50000;

class RpcClient
{
 public:

  RpcClient(asio::io_service& loop, const std::string& remote_addr, int remote_port)
    : // loop_(loop),
      client_(std::make_shared<easyasio::net::TcpClient>(loop, remote_addr, remote_port)),
      channel_(new easyasio::net::RpcChannel),
      stub_(channel_.get())
    {
        client_->setConnectionCallback(
            std::bind(&RpcClient::onConnection, this, std::placeholders::_1));
        client_->setMessageCallback(
            std::bind(&easyasio::net::RpcChannel::onMessage, channel_.get(), std::placeholders::_1, std::placeholders::_2));
    }

    void connect()
    {
        client_->asynConnect();
    }

    void sendRequest()
    {
        echo::EchoRequest request;
        request.set_payload("001010");
        echo::EchoResponse* response = new echo::EchoResponse;
        stub_.Echo(NULL, &request, response, NewCallback(this, &RpcClient::replied, response));
    }

private:
    void onConnection(const easyasio::net::TcpConnectionPtr& conn)
    {
        if (conn->connected())
        {
            //channel_.reset(new RpcChannel(conn));
            conn->setTcpNoDelay(true);
            channel_->setConnection(conn);
            sendRequest();
        }
    }

    void replied(echo::EchoResponse* resp)
    {
        LOG_INFO("recv reply {}", resp->payload());
    }
private:
    std::shared_ptr<easyasio::net::TcpClient> client_;
    easyasio::net::RpcChannelPtr channel_;
    echo::EchoService::Stub stub_;
};

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        printf("usage: ./client remoteaddr port\n");
        exit(-1);
    }

    asio::io_service loop;
    std::string addr(argv[1]);
    int port = atoi(argv[2]);
    RpcClient client(loop, addr, port);
    client.connect();
    loop.run();

    int x;
    std::cin >> x;
}

